home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-19
/
iritsm3s.zip
/
POLY3D-R.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-01-12
|
20KB
|
562 lines
/*****************************************************************************
* Program to draw 3D object as solid objects in GIF image file format. *
* *
* Options: *
* 1. -a ambient : Ratio of the ambient color. *
* 2. -c n : Number of bit ber pixel (2^n is number of colors possible). *
* 3. -l x y z : Light source direction vector. *
* 4. -2 : Force 2 light sources at opposite direction of light vectors. *
* 5. -m : More flag, to print more imformation on input/errors. *
* 6. -s x y : Specify new dimensions to generate the resulting image. *
* 7. -S SubSample : specifies dimension of pixel sub sampling (1..4). *
* 8. -g : Use gouraud shading. *
* 9. -b : Delete Back facing polygons. *
* 10. -M Mask : Create boolean Mask (coverage) image as well. *
* 11. -z : Print current version, and some helpfull data. *
* 12. -f FineNess : log based 2 of the surface to polygons subdiv, fineness. *
* *
* Note some of those options may be permanently set to a different default *
* using the configuration file "Poly3D-R.cfg" *
* *
* Usage: poly3d-r [-a Ambient] [-c N] [-l X Y Z] [-2] [-m] [-s Xsize Ysize] *
* [-S SubSample] [-g] [-b] [-M Mask] [-z] [-f FineNess] DFiles *
* *
* Written by: Gershon Elber Ver 3.0, Aug 1990 *
*****************************************************************************/
#ifdef __MSDOS__
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <io.h>
#include <dos.h>
#include <alloc.h>
#endif /* __MSDOS__ */
#include <stdio.h>
#include <math.h>
#include <time.h>
#include "program.h"
#include "getarg.h"
#include "genmat.h"
#include "iritprsr.h"
#include "config.h"
#ifdef __TURBOC__ /* Malloc debug routine - only on TC++ 1.0 and above. */
#define __DEBUG_MALLOC__
#endif /* __TURBOC__ */
#ifdef __MSDOS__
/* This huge stack is mainly from second phase - the segment intersections */
/* which may cause recursive calls - a lot... */
extern unsigned int _stklen = 32766;
#endif /* __MSDOS__ */
#ifdef NO_CONCAT_STR
static char *VersionStr =
"Poly3D-R Version 3.0, Gershon Elber,\n\
(C) Copyright 1989/90/91 Gershon Elber, Non commercial use only.";
#else
static char *VersionStr = "Poly3D-R " VERSION ", Gershon Elber, "
__DATE__ ", " __TIME__ "\n"
"(C) Copyright 1989/90/91 Gershon Elber, Non commercial use only.";
#endif /* NO_CONCAT_STR */
static char *CtrlStr =
#ifdef __MSDOS__
"poly3d-r a%-Ambient!f c%-N!d l%-X|Y|Z!f!f!f 2%- m%- s%-Xsize|Ysize!d!d S%-SubSample!d g%- b%- M%-Mask!s z%- f%-FineNess!d DFiles!*s";
#else
"poly3d-r a%-Ambient!F c%-N!d l%-X|Y|Z!F!F!F 2%- m%- s%-Xsize|Ysize!d!d S%-SubSample!d g%- b%- M%-Mask!s z%- f%-FineNess!d DFiles!*s";
#endif /* __MSDOS__ */
static long SaveTotalTime;
static GifColorType MaskColorMap[2] = { /* Boolean mask GIF file color map. */
{ 0, 0, 0 },
{ 255, 255, 255 }
};
/* Fineness surface subdivision control. */
static int GlblFineNess = DEFAULT_FINENESS;
int GlblNumOfPolys = 0; /* Total number of polygons scan converted. */
int GlblNumOfVerts = 0; /* Total number of vertices. */
MatrixType GlblViewMat; /* Current view of object. */
/* Amount scene was scaled up from normalized [-1..1] size on both X & Y: */
RealType GlblScaleUpFctr = 0.0;
/* The following are setable variables (via configuration file poly3d-h.cfg).*/
int GlblMore = FALSE;
ShadeInfoStruct GlblShadeInfo = {
1, /* Sub samples per pixel. */
DEFAULT_BITS_PER_PIXEL,
0,
DEFAULT_COLOR,
DEFAULT_BACK_GROUND_COLOR,
FALSE, /* No two light sources. */
DEFAULT_SCREEN_XSIZE,
DEFAULT_SCREEN_YSIZE,
FALSE, /* No Gouraud shading. */
FALSE, /* No back facing deletion. */
NULL,
NULL, /* No color map yet. */
DEFAULT_LIGHT_SOURCE,
DEFAULT_AMBIENT,
DEFAULT_NORMAL_AVG_DEGREE
};
static ConfigStruct SetUp[] = {
{ "Ambient", (VoidPtr) &GlblShadeInfo.Ambient, SU_REAL_TYPE },
{ "LightSrcX", (VoidPtr) &GlblShadeInfo.LightSource[0],SU_REAL_TYPE },
{ "LightSrcY", (VoidPtr) &GlblShadeInfo.LightSource[1],SU_REAL_TYPE },
{ "LightSrcZ", (VoidPtr) &GlblShadeInfo.LightSource[2],SU_REAL_TYPE },
{ "AvgDegree", (VoidPtr) &GlblShadeInfo.NrmlAvgDegree, SU_REAL_TYPE },
{ "TwoSources", (VoidPtr) &GlblShadeInfo.TwoSources, SU_BOOLEAN_TYPE },
{ "Gouraud", (VoidPtr) &GlblShadeInfo.Gouraud, SU_BOOLEAN_TYPE },
{ "backFacing", (VoidPtr) &GlblShadeInfo.BackFacing, SU_BOOLEAN_TYPE },
{ "SubSample", (VoidPtr) &GlblShadeInfo.SubSamplePixel,SU_INTEGER_TYPE },
{ "BitsPerPixel", (VoidPtr) &GlblShadeInfo.BitsPerPixel, SU_INTEGER_TYPE },
{ "Color", (VoidPtr) &GlblShadeInfo.DefaultColor, SU_INTEGER_TYPE },
{ "BackGroundColor", (VoidPtr) &GlblShadeInfo.BackGroundColor,SU_INTEGER_TYPE },
{ "Xsize", (VoidPtr) &GlblShadeInfo.ScrnXSize, SU_INTEGER_TYPE },
{ "Ysize", (VoidPtr) &GlblShadeInfo.ScrnYSize, SU_INTEGER_TYPE },
{ "FineNess", (VoidPtr) &GlblFineNess, SU_INTEGER_TYPE },
{ "More", (VoidPtr) &GlblMore, SU_BOOLEAN_TYPE }
};
#define NUM_SET_UP (sizeof(SetUp) / sizeof(ConfigStruct))
/* All polygons to be scan convert will be inserted into this hash table */
/* during the preprocessing (PrepareXXXX functions). */
IPPolygonStruct **PolyHashTable;
static IPObjectStruct *MainGetDataFiles(char **DataFileNames, int NumOfDataFiles);
static IPPolygonStruct *Surface2Polygons(CagdSrfStruct *Srf);
/*****************************************************************************
* Main routine - Read Parameter line and do what you need... *
*****************************************************************************/
void
#ifdef __MSDOS__
cdecl /* So we can use -rp in Borland 3.0 (parameters in registers.). */
#endif /* __MSDOS__ */
main(int argc, char **argv)
{
int AmbientFlag = FALSE,
ColorFlag = FALSE,
LightSrcFlag = FALSE,
GifMaskFlag = FALSE,
VerFlag = FALSE,
NumFiles = 0,
ImageSizeFlag = FALSE,
SubSampleFlag = FALSE,
FineNessFlag = FALSE,
Error;
char *GifMaskName,
**FileNames = NULL;
RealType Size, Scale;
MatrixType Mat;
IPObjectStruct *PObjects;
GifFileType *GifFile,
*GifMask = NULL;
SaveTotalTime = time(NULL); /* Save starting time. */
#ifdef __MSDOS__
ctrlbrk((int cdecl (*)()) MyExit); /* Kill this program if ^C... */
#endif /* __MSDOS__ */
Config("poly3d-r", SetUp, NUM_SET_UP); /* Read config. file if exists. */
if ((Error = GAGetArgs (argc, argv, CtrlStr,
&AmbientFlag, &GlblShadeInfo.Ambient,
&ColorFlag, &GlblShadeInfo.BitsPerPixel, &LightSrcFlag,
&GlblShadeInfo.LightSource[0],
&GlblShadeInfo.LightSource[1],
&GlblShadeInfo.LightSource[2],
&GlblShadeInfo.TwoSources, &GlblMore, &ImageSizeFlag,
&GlblShadeInfo.ScrnXSize, &GlblShadeInfo.ScrnYSize,
&SubSampleFlag, &GlblShadeInfo.SubSamplePixel,
&GlblShadeInfo.Gouraud, &GlblShadeInfo.BackFacing,
&GifMaskFlag, &GifMaskName,
&VerFlag, &FineNessFlag, &GlblFineNess,
&NumFiles, &FileNames)) != 0) {
GAPrintErrMsg(Error);
GAPrintHowTo(CtrlStr);
MyExit(1);
}
if (GlblShadeInfo.Ambient < 0.0 || GlblShadeInfo.Ambient > 1.0) {
fprintf(stderr,
"Ambient light specified not in [0.0..1.0] range, %lf selected instead.\n",
DEFAULT_AMBIENT);
GlblShadeInfo.Ambient = DEFAULT_AMBIENT;
}
if (GlblShadeInfo.BitsPerPixel < 1 || GlblShadeInfo.BitsPerPixel > 8) {
fprintf(stderr,
"PitsPerPixel not in [1..8] range, %d selected instead.\n",
DEFAULT_BITS_PER_PIXEL);
GlblShadeInfo.BitsPerPixel = DEFAULT_BITS_PER_PIXEL;
}
Size = sqrt(SQR(GlblShadeInfo.LightSource[0]) +
SQR(GlblShadeInfo.LightSource[1]) +
SQR(GlblShadeInfo.LightSource[2]));
if (ABS(Size) < EPSILON) {
fprintf(stderr, "Light source vector is zero, Z axis selected instead.\n");
GlblShadeInfo.LightSource[0] =
GlblShadeInfo.LightSource[1] = 0.0;
GlblShadeInfo.LightSource[2] = 1.0;
}
else {
GlblShadeInfo.LightSource[0] /= Size;
GlblShadeInfo.LightSource[1] /= Size;
GlblShadeInfo.LightSource[2] /= Size;
}
if (VerFlag) {
fprintf(stderr, "\n%s\n\n", VersionStr);
GAPrintHowTo(CtrlStr);
ConfigPrint(SetUp, NUM_SET_UP);
MyExit(0);
}
if (!NumFiles) {
fprintf(stderr, "No data file names were given, exit.\n");
GAPrintHowTo(CtrlStr);
MyExit(1);
}
if (SubSampleFlag) {
if (GlblShadeInfo.SubSamplePixel < 1 || GlblShadeInfo.SubSamplePixel > 4) {
fprintf(stderr, "Sub sampling can be 1 to 4 only (1x1 to 4x4).\n");
GAPrintHowTo(CtrlStr);
MyExit(1);
}
}
/* Get the data files: */
IritPrsrPolyListCirc = FALSE;
PObjects = MainGetDataFiles(FileNames, NumFiles);
/* Compute the viewing matrices and related data: */
if (IritPrsrWasPrspMat)
MultTwo4by4(GlblViewMat, IritPrsrViewMat, IritPrsrPrspMat);
else
GEN_COPY(GlblViewMat, IritPrsrViewMat, sizeof(MatrixType));
/* Now its time to scale the normalized image (+/-1 on both X & Y) to */
/* size specified by the image dimensions. We scale up to the SMALLER */
/* dimension, and put the center at the image center. */
/* Also, as the GIF image starts at the top, we must flip the image */
/* along Y axis. */
GlblScaleUpFctr = Scale = MIN(GlblShadeInfo.ScrnXSize *
GlblShadeInfo.SubSamplePixel,
GlblShadeInfo.ScrnYSize *
GlblShadeInfo.SubSamplePixel) / 2.0;
GenMatScale(Scale, -Scale, Scale, Mat);
MultTwo4by4(GlblViewMat, GlblViewMat, Mat);
GenMatTrans(GlblShadeInfo.ScrnXSize * GlblShadeInfo.SubSamplePixel / 2.0,
GlblShadeInfo.ScrnYSize * GlblShadeInfo.SubSamplePixel / 2.0,
0.0, Mat);
MultTwo4by4(GlblViewMat, GlblViewMat, Mat);
/* Prepare data structures of objects themselves: */
PrepareViewData(PObjects);
/* Into shadingInfo global structure: */
PrepareColorTable(PObjects);
EvalVrtxColors(PObjects);
#ifndef DEBUG_NO_GIF
/* Open stdout for the GIF image file: */
if ((GifFile = EGifOpenFileHandle(1)) == NULL ||
EGifPutScreenDesc(GifFile,
GlblShadeInfo.ScrnXSize, GlblShadeInfo.ScrnYSize,
GlblShadeInfo.BitsPerPixel, 0,
GlblShadeInfo.BitsPerPixel, GlblShadeInfo.PColorMap) ==
GIF_ERROR ||
EGifPutImageDesc(GifFile,
0, 0, GlblShadeInfo.ScrnXSize, GlblShadeInfo.ScrnYSize, FALSE,
GlblShadeInfo.BitsPerPixel, NULL) == GIF_ERROR)
QuitGifError();
/* Open special mask file if required: */
if (GifMaskFlag &&
((GifMask = EGifOpenFileName(GifMaskName, FALSE)) == NULL ||
EGifPutScreenDesc(GifMask,
GlblShadeInfo.ScrnXSize, GlblShadeInfo.ScrnYSize,
1, 0, 1, MaskColorMap) == GIF_ERROR ||
EGifPutImageDesc(GifMask, 0, 0,
GlblShadeInfo.ScrnXSize, GlblShadeInfo.ScrnYSize,
FALSE, 1, NULL) == GIF_ERROR))
QuitGifError();
#endif /* DEBUG_NO_GIF */
ScanConvertData(GifFile, GifMask); /* Do the real interesting stuff... */
#ifndef DEBUG_NO_GIF
EGifCloseFile(GifFile);
if (GifMask) EGifCloseFile(GifMask);
#endif /* DEBUG_NO_GIF */
MyExit(0);
}
/*****************************************************************************
* Main routine to read the data description files: *
* Returns pointer to pointers on FileDescription structures (one per file). *
*****************************************************************************/
static IPObjectStruct *MainGetDataFiles(char **DataFileNames, int NumOfDataFiles)
{
int i;
char *ErrorMsg;
FILE *f;
long
SaveTime = time(NULL);
IPObjectStruct *PObj, *PObjTail,
*PObjHead = NULL;
fprintf(stderr, "Reading data file(s).\n");
for (i = 0; i < NumOfDataFiles; i++) {
if (GlblMore) fprintf(stderr, "Reading %s.\n", *DataFileNames);
#ifdef __MSDOS__
if ((f = fopen(*DataFileNames, "rt")) == NULL) { /* Open the file. */
#else
if ((f = fopen(*DataFileNames, "r")) == NULL) { /* Open the file. */
#endif /* __MSDOS__ */
fprintf(stderr, "Can't open data file %s.\n", *DataFileNames);
MyExit(1);
}
if ((PObj = IritPrsrGetObjects(f)) != NULL) { /* Get the data file. */
PObjTail = PObj;
while (PObjTail -> Pnext) PObjTail = PObjTail -> Pnext;
PObjTail -> Pnext = PObjHead;
PObjHead = PObj;
}
if (GlblMore && IritPrsrParseError(&ErrorMsg))
fprintf(stderr, "File %s, %s\n", *DataFileNames, ErrorMsg);
fclose(f); /* Close the file. */
DataFileNames++; /* Skip to next file name. */
}
if (PObjHead == NULL) {
fprintf(stderr, "No data found.\n");
MyExit(1);
}
fprintf(stderr, "Done reading, %ld seconds.", time(NULL) - SaveTime);
return PObjHead;
}
/*****************************************************************************
* Routine to convert all surfaces/curves into polylines as follows: *
* Curves are converted to single polyline with SamplesPerCurve samples. *
* Surface are converted into GlblNumOfIsolines curves in each axes, each *
* handled as Curves above. The curves and surfaces are then deleted. *
*****************************************************************************/
IPObjectStruct *IritPrsrProcessFreeForm(IPObjectStruct *CrvObjs,
IPObjectStruct *SrfObjs)
{
CagdCrvStruct *Crvs;
CagdSrfStruct *Srf, *Srfs;
IPObjectStruct *PObj, *PObjNext;
IPPolygonStruct *PPolygon, *PPolygonTemp;
if (CrvObjs == NULL && SrfObjs == NULL) return NULL;
/* Make sure requested format is something reasonable. */
if (GlblFineNess < 2) {
GlblFineNess = 2;
if (GlblMore)
fprintf(stderr, "FineNess is less than 2, 2 picked instead.\n");
}
if (CrvObjs) {
/* Curves are not rendered at this time and they are ignored. */
for (PObj = CrvObjs; PObj != NULL;) {
Crvs = PObj -> U.PCrvs;
CagdCrvFreeList(Crvs);
PObjNext = PObj -> Pnext;
free(PObj);
PObj = PObjNext;
}
CrvObjs = NULL;
}
if (SrfObjs) {
for (PObj = SrfObjs; PObj != NULL; PObj = PObj -> Pnext) {
Srfs = PObj -> U.PSrfs;
PObj -> U.PPolygon = NULL;
for (Srf = Srfs; Srf != NULL; Srf = Srf -> Pnext) {
PPolygon = PPolygonTemp = Surface2Polygons(Srf);
while (PPolygonTemp -> Pnext)
PPolygonTemp = PPolygonTemp -> Pnext;
PPolygonTemp -> Pnext = PObj -> U.PPolygon;
PObj -> U.PPolygon = PPolygon;
}
CagdSrfFreeList(Srfs);
}
}
return SrfObjs;
}
/*****************************************************************************
* Routine to convert a single surface into a polygons with GlblFineNess *
* samples as the subdivision fineness measure. *
*****************************************************************************/
static IPPolygonStruct *Surface2Polygons(CagdSrfStruct *Srf)
{
int i, j;
IPVertexStruct *V, *VHead;
IPPolygonStruct *P,
*PHead = NULL;
CagdPolygonStruct *CagdPolygon,
*CagdPolygonHead = NULL;
CagdPolygonHead = CagdSrf2Polygons(Srf, 1 << GlblFineNess, TRUE, TRUE);
for (CagdPolygon = CagdPolygonHead;
CagdPolygon != NULL;
CagdPolygon = CagdPolygon -> Pnext) {
/* All polygons are triangles! */
for (i = 0, VHead = NULL; i < 3; i++) { /* Convert to vertices. */
if (VHead == NULL)
VHead = V = IritPrsrNewVertexStruct();
else {
V -> Pnext = IritPrsrNewVertexStruct();
V = V -> Pnext;
}
IP_SET_VRTX_NORMAL(V); /* Vertex has normal. */
for (j = 0; j < 3; j++) /* Convert to our format. */
V -> Coord[j] = CagdPolygon -> Polygon[i].Pt[j];
for (j = 0; j < 3; j++)
V -> Normal[j] = CagdPolygon -> Normal[i].Vec[j];
}
P = IritPrsrNewPolygonStruct();
P -> PVertex = VHead;
P -> Type = IP_POLYGON;
P -> Pnext = PHead;
PHead = P;
}
CagdPolygonFreeList(CagdPolygonHead);
return PHead;
}
#ifdef __DEBUG_MALLOC__
/*****************************************************************************
* My Routine to allocate dynamic memory. All program requests must call this *
* routine (no direct call to malloc). Dies if no memory. *
*****************************************************************************/
static void AllocError(const char *Msg, VoidPtr *p)
{
fprintf(stderr, "%s, Ptr = %p\n", Msg, p);
MyExit(3);
}
#endif /* __DEBUG_MALLOC__ */
/*****************************************************************************
* My Routine to allocate dynamic memory. All program requests must call this *
* routine (no direct call to malloc). Dies if no memory. *
*****************************************************************************/
VoidPtr MyMalloc(unsigned size)
{
VoidPtr p;
if ((p = malloc(size)) != NULL) return p;
fprintf(stderr, "Not enough memory, exit.\n");
MyExit(2);
return NULL; /* Make warnings silent. */
}
/*****************************************************************************
* My Routine to free dynamic memory. All program requests must call this *
* routine (no direct call to free). *
*****************************************************************************/
void MyFree(VoidPtr p)
{
#ifdef __DEBUG_MALLOC__
switch (heapchecknode(p)) {
case _HEAPCORRUPT:
AllocError("Heap is corrupted", p);
break;
case _BADNODE:
AllocError("Attempt to free a bogus pointer", p);
break;
case _FREEENTRY:
AllocError("Attempt to free an already freed pointer", p);
break;
case _USEDENTRY:
break;
default:
AllocError("Allocation error", p);
break;
}
#endif /* __DEBUG_MALLOC__ */
free(p);
}
/*****************************************************************************
* Trap Cagd_lib errors right here. *
*****************************************************************************/
void CagdFatalError(CagdFatalErrorType ErrID)
{
char
*ErrorMsg = CagdDescribeError(ErrID);
fprintf(stderr, "CAGD_LIB: %s", ErrorMsg);
exit(-1);
}
/*****************************************************************************
* MyExit routine. Note it might call to CloseGraph without calling *
* InitGraph(), or call MouseClose() without MouseInit(), or call *
* RestoreCtrlBrk() without SetUpCtrlBrk() and it is the responsibility *
* of the individual modules to do nothing in these cases. *
*****************************************************************************/
void MyExit(int ExitCode)
{
#ifdef __MSDOS__
fprintf(stderr,
"\nPoly3D-R: Total RealTime %ld seconds, Core left %ldk.\n",
time(NULL) - SaveTotalTime, coreleft() / 1024);
#else
fprintf(stderr,
"\nPoly3D-R: Total RealTime %ld seconds.\n",
time(NULL) - SaveTotalTime);
#endif /* __MSDOS__ */
exit(ExitCode);
}
/******************************************************************************
* Close output file (if open), and exit. *
******************************************************************************/
void QuitGifError(void)
{
PrintGifError();
MyExit('G');
}